#include "_head_unsort_loop.h"

void init(Node_t** head, int size)
{
	*head = (Node_t*)malloc(sizeof(Node_t));
	assert(*head);
	(*head)->data = NULL;
	(*head)->next = *head;
	(*head)->prev = *head;
	(*head)->size = size;
	(*head)->count = 0;
}


void push_back(Node_t* head, void* newnode)
{
	Node_t* new = (Node_t*)malloc(sizeof(Node_t));
	assert(new);

	new->size = head->size;
	new->next = NULL;
	new->prev = NULL;
	new->count = head->count++;
	new->data = (void*)malloc(head->size);
	assert(new->data);
	memcpy(new->data, newnode, head->size);

	new->prev = head->prev;
	new->next = head;
	head->prev->next = new;
	head->prev = new;

	head->count++;

	
}

void push_front(Node_t* head, void* newnode)
{
	Node_t* new = (Node_t*)malloc(sizeof(Node_t));
	assert(new);
	new->size = head->size;
	new->next = NULL;
	new->prev = NULL;
	new->count = head->count++;
	new->data = (void*)malloc(head->size);
	assert(new->data);
	memcpy(new->data, newnode, head->size);

	new->prev = head;
	new->next = head->next;
	head->next->prev = new;
	head->next = new;

	head->count++;
	
}


void push_pos(Node_t* head, int pos, void* newnode)
{
	
	Node_t* new = (Node_t*)malloc(sizeof(Node_t));
	assert(new);
	new->size = head->size;
	new->next = NULL;
	new->next = NULL;
	new->count = head->count++;
	new->data = (void*)malloc(head->size);
	assert(new->data);
	memcpy(new->data, newnode, head->size);

	int i = 0;
	while(i < pos && head->next != NULL)
	{
		head = head->next;
		i++;
	}

	
	new->prev = head->prev;
	new->next = head;
	head->prev->next = new;
	head->prev = new;

	head->count++;
}

void* find_pos(Node_t* head, int pos)
{
	int i = 0;
	Node_t* tmp = head;
	while(i < pos && head->next != head)
	{
		head = head->next;
		i++;
	}
	return head->next;
}

void* find_front(Node_t* head, void* key, func_cmp_t cmp)
{
	Node_t* tmp = head;
	while(head->next != tmp)
	{
		if(cmp(head->next, key) == 0)
		{
			return head->next;
		}

		head = head->next;
	}

	return NULL;
}

void* find_back(Node_t* head, void* key, func_cmp_t cmp)
{
	Node_t* tmp = head;
	while(head->prev != tmp)
	{
		if(cmp(head->prev, key) == 0)
		{
			return head = head->prev;
		}
		head = head->prev;
	}
	return NULL;
}

Node_t* find_All(Node_t* head, void* key, func_cmp_t cmp)
{
	Node_t* tmphead = NULL;
	init(&tmphead, head->size);

	Node_t* tmp = head;
	while(head->next != tmp)
	{
		if(cmp(head->next, key) == 0)
		{
			push_back(tmphead, key);
		}

		head = head->next;
	}
	return tmphead;
}

void mod_front(Node_t* head, void* oldKey, func_cmp_t cmp, void* newKey, func_mod_t mod)
{
	void* modNode = find_front(head, oldKey, cmp);
	mod(modNode, newKey);
}


void mod_back(Node_t* head, void* oldKey, func_cmp_t cmp, void* newKey, func_mod_t mod)
{
	void* modNode = find_back(head, oldKey, cmp);
	mod(modNode, newKey);
}

void mod_All(Node_t* head, void* oldKey, func_cmp_t cmp, void* newKey, func_mod_t mod)
{
	void* modTmp = find_front(head, oldKey, cmp);
	while(modTmp != NULL)
	{
		mod(modTmp, newKey);
		modTmp = find_front(head, oldKey, cmp);
	}
}

void mod_pos(Node_t* head, int pos, void* newKey, func_mod_t mod)
{
	void* modTmp = find_pos(head, pos);
	mod(modTmp, newKey);
}

void pop_front(Node_t* head, void* key, func_cmp_t cmp)
{
	Node_t* node = find_front(head, key, cmp);

	if(node == NULL)
	{
		return;
	}

	node->prev->next = node->next;
	node->next->prev = node->prev;
	free(node);

	head->count--;

}

void pop_back(Node_t* head, void* key, func_cmp_t cmp)
{
	Node_t* node = find_back(head, key, cmp);

	if(node == NULL)
	{
		return;
	}

	node->prev->next = node->next;
	node->next->prev = node->prev;
	free(node);

	head->count--;

}

void pop_All(Node_t* head, void* key, func_cmp_t cmp)
{
	Node_t* node = find_front(head, key, cmp);

	while(node != NULL)
	{
		node->prev->next = node->next;
		node->next->prev = node->prev;
		free(node);
		head->count--;
		node = find_front(head, key, cmp);
	}

}

void pop_pos(Node_t* head, int pos)
{
	Node_t* node = find_pos(head, pos);

	if(node == NULL)
	{
		return;
	}
	node->prev->next = node->next;
	node->next->prev = node->prev;
	free(node);

	head->count--;
}

void list_write(Node_t* head, char* path)
{
	FILE* fp = fopen(path, "w");
	assert(fp);

	int flag = fwrite(&(head->size), sizeof(head->size), 1, fp);
	assert(flag == 1);
	flag = fwrite(&(head->count), sizeof(head->count), 1, fp);
	assert(flag == 1);

	Node_t* tmp = head->next;
	for(; tmp != head; tmp = tmp->next)
	{
		flag = fwrite(tmp->data, head->size, 1, fp);
		assert(flag == 1);
		
	}
	
	fclose(fp);
}

void list_read(Node_t* head, char* path)
{
	FILE* fp = fopen(path, "r");
	assert(fp);

	int flag = fread(&(head->size), sizeof(head->size), 1, fp);
	assert(flag == 1);

	flag = fread(&(head->count), sizeof(head->count), 1, fp);
	assert(flag == 1);

	void* buff = malloc(head->size);

	while(flag == 1)
	{
		flag = fread(buff, head->size, 1, fp);
		push_back(head, buff);
	}

	free(buff);
}

void print(Node_t* head, func_print_t ls)
{
	Node_t* tmp = head;
	while(head->next != tmp)
	{
		ls(head->next);
		head = head->next;
	}
	putchar(10);
}

void destory(Node_t* head)
{
	Node_t* Tmp = head;
	while(head->next != Tmp)
	{
		Node_t* tmp = head->next->next;
		free(head->next);
		head->next = tmp;
	}
}



Node_t* reversal_list(Node_t* head)
{
	Node_t* pre = NULL;
	Node_t* cur = head;
	Node_t* next = head->next;

	while(next != NULL)
	{
		cur->next = pre;
		pre = cur;
		cur = next;
		next = next->next;
	}
	cur->next = pre;
	return cur;
}
